package com.evan.webadmin.upms.listener;

import cn.hutool.json.JSONUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.util.ListUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.evan.common.core.constant.GlobalDeletedFlag;
import com.evan.common.core.object.TokenData;
import com.evan.common.sequence.wrapper.IdGeneratorWrapper;
import com.evan.webadmin.upms.dto.ImportErrorDto;
import com.evan.webadmin.upms.dto.SysUserImportDto;
import com.evan.webadmin.upms.model.SysDataPermUser;
import com.evan.webadmin.upms.model.SysUser;
import com.evan.webadmin.upms.model.SysUserPost;
import com.evan.webadmin.upms.model.SysUserRole;
import com.evan.webadmin.upms.model.constant.SysUserStatus;
import com.evan.webadmin.upms.model.constant.SysUserType;
import com.evan.webadmin.upms.service.SysUserRoleService;
import com.evan.webadmin.upms.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Component
public class SysUserExcelListener extends AnalysisEventListener<SysUserImportDto> {

    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysUserRoleService sysUserRoleService;
    @Autowired
    private IdGeneratorWrapper idGenerator;
    @Autowired
    private PasswordEncoder passwordEncoder;

    private static final int BATCH_COUNT = 100;

    private static final String DEFAULT_PASSWORD = "123456";
    private static final String ROLE_CUSTOM = "1802145997401362432";
    private static final String ROLE_ENTERPRISE = "1800377615874265088";

    private static final String DEFAULT_DEPT_ID = "1781545342076981250";

    private static final String CUSTOM_DEPT_ID = "1800374343138545664";

    private static final String ENTERPRISE_DEPT_ID = "1800374542359597056";

    private static final String CUSTOM_TYPE_NAME = "海关用户";


    /**
     * 缓存的数据
     */
    private ArrayList<SysUserImportDto> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    private List<ImportErrorDto> errorList = new ArrayList<>();
    private List<SysUserRole> userRoles = new ArrayList<>();
    private List<SysUserPost> userPosts = new ArrayList<>();
    private List<SysDataPermUser> dataPermUsers = new ArrayList<>();

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        log.info("解析表头");
        log.info(JSONUtil.toJsonStr(headMap));
    }

    @Override
    public void onException(Exception exception, AnalysisContext context) {
        int rowIndex = context.readRowHolder().getRowIndex();

        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
            log.error("第{}行，第{}列解析异常，数据为:{}", excelDataConvertException.getRowIndex(), excelDataConvertException.getColumnIndex(), excelDataConvertException.getCellData());
            errorList.add(new ImportErrorDto(null, excelDataConvertException.getRowIndex(), "解析异常"));
        }else{
            log.error("第{}行解析异常:{}", rowIndex, exception.getMessage());
            errorList.add(new ImportErrorDto(null, context.readRowHolder().getRowIndex(), "解析异常"));
        }
        log.info("继续解析下一行");

    }

    @Override
    public void invoke(SysUserImportDto user, AnalysisContext analysisContext) {
        StringBuilder errorMessage = new StringBuilder();

        // 验证字段不能为空
        if (user.getLoginName() == null || user.getLoginName().isEmpty()) {
            errorMessage.append("登录名不能为空; ");
        }
        if (user.getUserName() == null || user.getUserName().isEmpty()) {
            errorMessage.append("用户名不能为空; ");
        }
        if (user.getUserType() == null || user.getUserType().isEmpty()) {
            errorMessage.append("用户类型不能为空; ");
        }

        // 验证登录名唯一性
        if (sysUserService.count(new LambdaQueryWrapper<SysUser>().eq(SysUser::getLoginName, user.getLoginName())) > 0) {
            errorMessage.append("登录名已存在; ");
        }

        // 如果有错误，记录错误信息
        if (errorMessage.length() > 0) {
            ImportErrorDto error = new ImportErrorDto(user, analysisContext.readRowHolder().getRowIndex(), errorMessage.toString());
        } else {
            cachedDataList.add(user); // 添加到待插入列表
        }
        // 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
        if (cachedDataList.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
            userRoles = new ArrayList<>();
        }
    }

    private void saveData() {
        log.info("{}条数据，开始存储数据库！", cachedDataList.size());
        //存储
        if(cachedDataList != null && cachedDataList.size() > 0){
            List<SysUser> users = assemblyUsers(cachedDataList);
            sysUserService.saveBatch(users);
            saveUserRoles(users);
            //saveUserPost(users);
        }
        log.info("存储数据库成功！");
    }

    private void saveUserPost(List<SysUser> users) {
        userPosts = users.stream().map(user -> {
SysUserPost sysUserPost = new SysUserPost();
            sysUserPost.setUserId(user.getUserId());
            return sysUserPost;
        }).collect(Collectors.toList());
    }

    private void saveUserRoles(List<SysUser> users) {
        userRoles = users.stream().map(user -> {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setUserId(user.getUserId());
            if(CUSTOM_DEPT_ID.equals(user.getDeptId())){
                sysUserRole.setRoleId(ROLE_CUSTOM);
            } else{
                sysUserRole.setRoleId(ROLE_ENTERPRISE);
            }
            return sysUserRole;
        }).collect(Collectors.toList());
        sysUserRoleService.saveBatch(userRoles);
    }

    private List<SysUser> assemblyUsers(ArrayList<SysUserImportDto> cachedDataList) {
        return cachedDataList.stream().map(user -> {
            SysUser sysUser = new SysUser();
            sysUser.setLoginName(user.getLoginName());
            sysUser.setShowName(user.getUserName());
            sysUser.setMobile(user.getMobile());
            sysUser.setEmail(user.getEmail());
            sysUser.setUserType(SysUserType.TYPE_USER);
            sysUser.setUserId(idGenerator.nextStringId());
            sysUser.setPassword(passwordEncoder.encode(DEFAULT_PASSWORD));
            sysUser.setUserStatus(SysUserStatus.STATUS_NORMAL);
            sysUser.setDeletedFlag(GlobalDeletedFlag.NORMAL);
            sysUser.setDeptId(CUSTOM_TYPE_NAME.equals(user.getUserType())?CUSTOM_DEPT_ID:ENTERPRISE_DEPT_ID);
            sysUser.setCreateBy(TokenData.takeFromRequest().getUserId());
            sysUser.setCreateTime(new Date());
            sysUser.setUpdateBy(TokenData.takeFromRequest().getUserId());
            sysUser.setUpdateTime(new Date());
            return sysUser;
        }).collect(Collectors.toList());
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        saveData();
        log.info("解析完毕");
        cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    }

    @Override
    public boolean hasNext(AnalysisContext context) {
        return super.hasNext(context);
    }

    public List<ImportErrorDto> getErrorList() {
        return errorList;
    }
}